/* Turska Framework/UI library (Turs2)
 * Copyright 2003-2010 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/turska/
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: T2IMGUIImage9TileButtonStyle.cpp 28 2012-07-28 17:03:06Z trzntaat $
 * $Revision: 28 $
 */

#include <math.h>
#include <assert.h>

#include "Turs2.h"


namespace turska
{


static I32 sMax(I32 a, I32 b)
{
    return a > b ? a : b;
}


IMGUIImage9TileButtonStyle::IMGUIImage9TileButtonStyle(Font *font, Image9Tile *imageUp, Image9Tile *imageHot,
                                                       Image9Tile *imageActive, Image9Tile *imageHotDown) :
    mScale(1),
    mRefImage(0),
    mMinWidth(0), mMinHeight(0),
    mShadowEnabled(false),
    mTextXOffset(0), mTextYOffset(0),
    mImageXOffset(0), mImageYOffset(0),
    mShadowXOffset(0), mShadowYOffset(2.5f),
    mButtonDownTextXOffset(0), mButtonDownTextYOffset(2.0f),
    mButtonDownImageXOffset(0), mButtonDownImageYOffset(2.0f),
    mTextFlags(IF_ALIGN_CENTER), mImageFlags(IF_ALIGN_CENTER),
    mTextDrawMode(IDM_NORMAL), mImageDrawMode(IDM_NORMAL), mButtonImageDrawMode(IDM_NORMAL),
    mTextScale(1), mKeyFocusAllowed(true), mActivateFromUpEvent(true)
{
    mButtonColor.set(0xffffffff);
    mImageColor.set(0xffffffff);
    mTextColor.set(0xffffffff);
    mShadowMultiplierColor.set(0x80000000);
    mFont = font;
    mImages[IMGUI_WS_DEFAULT] = imageUp;
    mImages[IMGUI_WS_HOT] = imageHot;
    mImages[IMGUI_WS_ACTIVE] = imageActive;
    mImages[IMGUI_WS_HOT_ACTIVE] = imageHotDown;
    Image9Tile *img = mImages[IMGUI_WS_DEFAULT];
    if (img == 0)
        img = mImages[IMGUI_WS_HOT];
    if (img == 0)
        img = mImages[IMGUI_WS_ACTIVE];
    if (img == 0)
        img = mImages[IMGUI_WS_HOT_ACTIVE];
    if (img != 0)
    {
        mMinWidth = img->getMinimumWidth();
        mMinHeight = img->getMinimumHeight();
        mRefImage = img;
    }
    assert(mRefImage != 0);
}


void IMGUIImage9TileButtonStyle::getSize(I32 &oWidth, I32 &oHeight, const C8 *text, Image *image)
{
    const bool withBorder = mRefImage->isBorderOutside(); // can be moved to args if needed
    // these two rows would allow getSize resulting in smaller buttons than 9-tile's recommended minimum
    //oWidth = withBorder ? mMinWidth : mRefImage->getCenterWidth();
    //oHeight = withBorder ? mMinHeight : mRefImage->getCenterHeight();
    oWidth = mMinWidth;
    oHeight = mMinHeight;
    const I32 borderWidth = withBorder ? mRefImage->getLeftWidth() + mRefImage->getRightWidth() : 0;
    const I32 borderHeight = withBorder ? mRefImage->getTopHeight() + mRefImage->getBottomHeight() : 0;
    // TODO: what about image/text offset, should we take that into account for the button size?
    if (image != 0)
    {
        oWidth = sMax(oWidth, (I32)image->getWidth() + borderWidth);
        oHeight = sMax(oHeight, (I32)image->getHeight() + borderHeight);
    }
    if (text != 0 && mFont != 0)
    {
        TREAL textWidth = 0, textHeight = 0;
        mFont->getStringMetrics(textWidth, textHeight, text, mScale * mTextScale);
        oWidth = sMax(oWidth, (I32)ceilf(textWidth) + borderWidth);
        oHeight = sMax(oHeight, (I32)ceilf(textHeight) + borderHeight);
    }
}


bool IMGUIImage9TileButtonStyle::isInside(const IMGUI &imgui, TREAL x, TREAL y,
                                          const Rectangle &area,
                                          const C8 *text, Image *image)
{
    const bool haveCustomArea = (area.width != 0 && area.height != 0);
    Rectangle testArea = area;
    if (!haveCustomArea)
    {
        // no custom area - figure it out
        I32 width = 0, height = 0;
        getSize(width, height, text, image);
        testArea.width = (TREAL)width;
        testArea.height = (TREAL)height;
    }
    x -= testArea.x;
    y -= testArea.y;
    return x >= 0 && y >= 0 && x < testArea.width && y < testArea.height;
}


Rectangle IMGUIImage9TileButtonStyle::render(const IMGUI &imgui, I32 widgetState,
                                             TREAL x, TREAL y, TREAL width, TREAL height,
                                             const C8 *text, Image *image)
{
    assert(widgetState >= 0 && widgetState < IMGUI_WS_COUNT);
    const bool renderingEnabled = imgui.isRenderingEnabled();
    Image9Tile *buttonImage = mImages[widgetState];
    const UI32 buttonImageFlags = IF_COLOR | IF_ALPHA;
    UI32 insideImageFlags = IF_COLOR | IF_ALPHA;
    if (mScale != TREAL(1))
        insideImageFlags |= IF_TRANSFORM | IF_SCALE;
    else
        insideImageFlags |= IF_FORCE_INT;
    const bool haveCustomArea = (width != 0 && height != 0);
    if (!haveCustomArea)
    {
        I32 tmpWidth = 0, tmpHeight = 0;
        getSize(tmpWidth, tmpHeight, text, image);
        width = (TREAL)tmpWidth;
        height = (TREAL)tmpHeight;
        if (mRefImage->isBorderOutside())
        {
            x += mRefImage->getLeftWidth();
            y += mRefImage->getTopHeight();
            width -= mRefImage->getLeftWidth() + mRefImage->getRightWidth();
            height -= mRefImage->getTopHeight() + mRefImage->getBottomHeight();
        }
    } // !haveCustomArea

    if (renderingEnabled && buttonImage != 0)
    {
        buttonImage->draw(mButtonImageDrawMode, buttonImageFlags, x, y, width, height, mButtonColor);
    }

    const TREAL tlx = x, tly = y; // default align is top left
    TREAL tx = tlx, ty = tly;
    if (mTextFlags & IF_ALIGN_HORIZ_CENTER)
        tx += width / 2;
    else if (mTextFlags & IF_ALIGN_RIGHT)
        tx += width;
    if (mTextFlags & IF_ALIGN_VERT_CENTER)
        ty += height / 2;
    else if (mTextFlags & IF_ALIGN_BOTTOM)
        ty += height;
    tx = (TREAL)((I32)(tx + mTextXOffset));
    ty = (TREAL)((I32)(ty + mTextYOffset));
    TREAL ix = tlx, iy = tly;
    if (mImageFlags & IF_ALIGN_HORIZ_CENTER)
        ix += width / 2;
    else if (mImageFlags & IF_ALIGN_RIGHT)
        ix += width;
    if (mImageFlags & IF_ALIGN_VERT_CENTER)
        iy += height / 2;
    else if (mImageFlags & IF_ALIGN_BOTTOM)
        iy += height;
    ix = (TREAL)((I32)(ix + mImageXOffset));
    iy = (TREAL)((I32)(iy + mImageYOffset));

    if (mShadowEnabled)
    {
        TREAL shadowX = mScale * mShadowXOffset;
        TREAL shadowY = mScale * mShadowYOffset;

        // image/text shadow
        if (renderingEnabled && image != 0)
        {
            image->setScale(mScale);
            image->draw(IDM_NORMAL, insideImageFlags | mImageFlags,
                        ix + shadowX, iy + shadowY, mShadowMultiplierColor);
        }
        if (renderingEnabled && mFont != 0 && text != 0)
        {
            mFont->drawText(tx + shadowX, ty + shadowY, text, mTextFlags,
                            mScale * mTextScale, 0, mShadowMultiplierColor, 0);
        }
    }

    // image/text itself
    if (widgetState == IMGUI_WS_HOT_ACTIVE)
    {
        tx += mScale * mButtonDownTextXOffset;
        ty += mScale * mButtonDownTextYOffset;
        ix += mScale * mButtonDownImageXOffset;
        iy += mScale * mButtonDownImageYOffset;
    }
    if (renderingEnabled && image != 0)
    {
        image->setScale(mScale);
        image->draw(mImageDrawMode, insideImageFlags | mImageFlags, ix, iy, mImageColor);
    }
    if (renderingEnabled && mFont != 0 && text != 0)
    {
        const IMAGE_DRAW_MODE orgDrawMode = mFont->getDrawMode();
        mFont->setDrawMode(mTextDrawMode);
        mFont->drawText(tx, ty, text, mTextFlags, mScale * mTextScale, 0, mTextColor, 0);
        mFont->setDrawMode(orgDrawMode);
    }

    // Possible TODO: highlight text/image when hot
    if (widgetState & IMGUI_WS_MASK_HOT)
    {
    }

    Rectangle resultArea(x, y, width, height);
    if (!haveCustomArea && mRefImage->isBorderOutside())
    {
        resultArea.x -= mRefImage->getLeftWidth();
        resultArea.y -= mRefImage->getTopHeight();
        resultArea.width += mRefImage->getLeftWidth() + mRefImage->getRightWidth();
        resultArea.height += mRefImage->getTopHeight() + mRefImage->getBottomHeight();
    }

    return resultArea;
}


} // namespace turska
